import 'dart:convert';
import 'dart:developer';

import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter_rtk/common/config.dart';
import 'package:flutter_rtk/common/constants.dart';
import 'package:flutter_rtk/common/resp_dto.dart';
import 'package:flutter_rtk/service/event_bus_service.dart';
import 'package:flutter_rtk/service/events/logout_event.dart';
import 'package:flutter_rtk/service/store_service.dart';

class RequestUtils {
  RequestUtils._internal();

  factory RequestUtils() => _instance;
  static final RequestUtils _instance = RequestUtils._internal();

  // 实力化dio，链接超时默认10s超时
  static final _dio = createDioInstance();

  static Dio createDioInstance({int timeout = 12000}) {
    return Dio(BaseOptions(baseUrl: StoreService.to.getString(AppConstants.baseUrl), connectTimeout: timeout, receiveTimeout: timeout));
  }

  static dynamic request<T>({required String url, Map<String, dynamic>? params, Object? data, Options? options, int? timeout}) async {
    options ??= Options();
    Map<String, String> headers = {
      "Authorization": "Basic ${base64.encode("${AppConfig.clientId}:${AppConfig.clientSecret}".codeUnits)}",
      "Tenant-Id": AppConfig.defaultTenantId,
      "Sinoma-Auth": StoreService.to.getString(AppConstants.token),
    };
    options.headers = options.headers ?? {};
    options.headers!.addAll(headers);
    if (kDebugMode) {
      log("invoke url: ${options.method} $url ${params ?? data ?? ""}");
    }
    Response? response;
    try {
      if (timeout != null) {
        response = await createDioInstance(timeout: timeout).request(url, queryParameters: params, data: data, options: options);
      } else {
        response = await _dio.request(url, queryParameters: params, data: data, options: options);
      }
    } catch (e, stack) {
      debugPrintStack(stackTrace: stack, label: e.toString());
      response = (e as DioError).response;
    }
    if (response == null) {
      throw Exception("服务开小差了, 请稍后再试");
    }
    if (url == "/api/sinoma-auth/oauth/token") {
      return response.data;
    }
    if (response.statusCode == 200) {
      RespDTO<T> resp = RespDTO.fromJson(response.data);
      if (resp.success) {
        return resp.data;
      }
      debugPrint('invoke url finish: $url: ${resp.msg}');
      throw Exception(resp.msg);
    } else if (response.statusCode == 401) {
      EventBusService.fire(LogoutEvent("登录信息已过期，请重新登录"));
      return;
    }
    debugPrint('statusCode:${response.statusCode}, message:${response.statusMessage}');
    throw Exception("${response.statusCode}:${response.statusMessage}:${response.data}");
  }

  static dynamic get({required String url, Map<String, dynamic>? params, Map<String, String>? headers, int? timeout}) async {
    return request(url: url, params: params, options: Options(method: "GET", headers: headers), timeout: timeout);
  }

  static dynamic post({required String url, Map<String, dynamic>? params, Object? data, Map<String, String>? headers}) async {
    return request(url: url, params: params, data: data, options: Options(method: "POST", headers: headers));
  }

  static dynamic put({required String url, Object? data, Map<String, String>? headers}) async {
    return request(url: url, data: data, options: Options(method: "PUT", headers: headers));
  }

  static dynamic delete({required String url, Object? data, Map<String, String>? headers}) async {
    return request(url: url, data: data, options: Options(method: "DELETE", headers: headers));
  }

  static dynamic postWithForm({required String url, Map<String, dynamic>? params, Object? data, Map<String, String>? headers}) async {
    if (headers != null) {
      headers["Content-Type"] = "application/x-www-form-urlencoded";
    } else {
      headers = {"Content-Type": "application/x-www-form-urlencoded"};
    }
    return request(url: url, params: params, data: data, options: Options(method: "POST", headers: headers));
  }

  static dynamic upload({required String url, dynamic data, Map<String, String>? headers}) async {
    Map<String, String> headers = {
      "Authorization": "Basic ${base64.encode("${AppConfig.clientId}:${AppConfig.clientSecret}".codeUnits)}",
      "Tenant-Id": AppConfig.defaultTenantId,
      "Sinoma-Auth": StoreService.to.getString(AppConstants.token),
    };
    Response response = await _dio.post(url, data: FormData.fromMap({"file": data}), options: Options(headers: headers));
    return response.data;
  }

  static void download({required String url, dynamic savePath, Function? onReceiveProgress}) async {
    // Map<String, String> headers = {
    //   "Authorization": "Basic ${base64.encode("${AppConfig.clientId}:${AppConfig.clientSecret}".codeUnits)}",
    //   "Tenant-Id": AppConfig.defaultTenantId,
    //   "Sinoma-Auth": StoreService.to.getString(AppConstants.token),
    // };
    await _dio.download(url, savePath, onReceiveProgress: (int received, int total) {
      if (onReceiveProgress == null) {
        return;
      }
      if (total != -1) {
        double downloadRatio = (received / total);
        if (downloadRatio >= 1) {
          onReceiveProgress(1.0);
        } else {
          onReceiveProgress(downloadRatio);
        }
      }
    });
  }
}
